-
Notifications
You must be signed in to change notification settings - Fork 111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RSDK-9839: Have Go module clients be webrtc aware. #4751
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I think some other changes to grpc/shared_conn.go
and a couple other files slipped into here from the last version I saw?
I'll probably need a brief synchronous meeting to understand what's happening with the NewSharedConnForModule
function and some of the peer connection grabbing and setting. Or you can definitely bypass my review and get @nicksanford's or someone with more context. Up to you!
peerConnMu sync.Mutex | ||
peerConn *webrtc.PeerConnection | ||
peerConnReady <-chan struct{} | ||
peerConnClosed <-chan struct{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was unused
grpc/shared_conn.go
Outdated
|
||
ret.peerConn.OnTrack(func(trackRemote *webrtc.TrackRemote, rtpReceiver *webrtc.RTPReceiver) { | ||
sid := trackRemote.StreamID() | ||
if sid == "rtsp-1" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nicksanford , we need to do a real thing here. Not sure if the logic to put here is simple enough to communicate over a PR or if syncing in person would yield a better answer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets sync in person about this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | ||
logger := rc.Logger().Sublogger(resource.RemoveRemoteName(name).ShortName()) | ||
return apiInfo.RPCClient(rc.backgroundCtx, &rc.conn, rc.remoteName, name, logger) | ||
return apiInfo.RPCClient(rc.backgroundCtx, rc.getClientConn(), rc.remoteName, name, logger) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For @benjirewis 's edification, this is the thing we pass into the (camera) client constructor. Having this (newly added) getClientConn
to return a SharedConn
when (also new added) SetPeerConnection
was called is what allows this "camera client.PeerConn" call to return a non-nil value.
It's certainly the intention that only module programs go through this code path (due to calling SetPeerConnection
). And it's the intention that clients that never look at "clientConn.PeerConn" behave exactly the same (everything is funneled over the grpc.Dial("unix socker")
).
What's probably a better change (but a bit more movement/copying/uncertainty), that we can iterate towards, is having module/module.go
avoid calling "robotClient.ResourceByName". Such that we don't need to expose this RobotClient.SetPeerConnection
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that vaguely makes sense to me.
What's probably a better change (but a bit more movement/copying/uncertainty), that we can iterate towards, is having module/module.go avoid calling "robotClient.ResourceByName".
I suppose we've been treating the module -> rdk client connection as a regular Golang SDK client, but I can see it's now diverging slightly. I don't have as much context as you, but I might push to continue to use ResourceByName
unless you find that the module -> rdk gRPC client creation is more and more distinct from regular gRPC client creation. Just so we don't have to maintain two different gRPC client creation paths.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose we've been treating the module -> rdk client connection as a regular Golang SDK client
Well, our other option is to use gRPC over WebRTC for the module connections in which case this would work without modifications! Once we moved to webrtc and used its video tracks, rdk client behavior started to diverge.
This patch shoves that detail of how module connections are special into the robot Client. But by just calling (or not calling) SetPeerConnection. The only reason I prefer to not litter robot client with that detail is because of the whole "it's part of the public interface" for applications. I don't think I'd have an opinion if the two kinds of clients were distinct.
@@ -193,7 +232,7 @@ func (sc *SharedConn) ResetConn(conn rpc.ClientConn, moduleLogger logging.Logger | |||
} | |||
|
|||
sc.peerConn = peerConn | |||
sc.peerConnReady, sc.peerConnClosed, err = rpc.ConfigureForRenegotiation(peerConn, rpc.PeerRoleClient, sc.logger) | |||
sc.peerConnReady, _, err = rpc.ConfigureForRenegotiation(peerConn, rpc.PeerRoleServer, sc.logger) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to double check if we need PeerRoleServer or Client. And I ought to document the consequence of this choice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've confirmed this is in fact needed.
@benjirewis, I've redone this PR to officially be on top of what we just merged. And you're right that @nicksanford is a better candidate for the SharedConn changes. Your PR Benji can be scoped down to the module and robot client changes. I left a more detailed note on the diff. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally LGTM % Nick's review.
@@ -680,10 +688,10 @@ func (rc *RobotClient) ResourceByName(name resource.Name) (resource.Resource, er | |||
func (rc *RobotClient) createClient(name resource.Name) (resource.Resource, error) { | |||
apiInfo, ok := resource.LookupGenericAPIRegistration(name.API) | |||
if !ok || apiInfo.RPCClient == nil { | |||
return grpc.NewForeignResource(name, &rc.conn), nil | |||
return grpc.NewForeignResource(name, rc.getClientConn()), nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a comment at the top of the getClientConn
method that says: // Must be called with
rc.mu in ReadLock+ mode.
Are we doing that here? I assume the lock is already before we call createClient
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep -- need to unfold up a few lines: https://github.com/viamrobotics/rdk/pull/4751/files#diff-d6a5d93563cdb968513a4bc0246d93a5568b7233c639bfd2ba3e1d42c3925083R667
} | ||
logger := rc.Logger().Sublogger(resource.RemoveRemoteName(name).ShortName()) | ||
return apiInfo.RPCClient(rc.backgroundCtx, &rc.conn, rc.remoteName, name, logger) | ||
return apiInfo.RPCClient(rc.backgroundCtx, rc.getClientConn(), rc.remoteName, name, logger) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that vaguely makes sense to me.
What's probably a better change (but a bit more movement/copying/uncertainty), that we can iterate towards, is having module/module.go avoid calling "robotClient.ResourceByName".
I suppose we've been treating the module -> rdk client connection as a regular Golang SDK client, but I can see it's now diverging slightly. I don't have as much context as you, but I might push to continue to use ResourceByName
unless you find that the module -> rdk gRPC client creation is more and more distinct from regular gRPC client creation. Just so we don't have to maintain two different gRPC client creation paths.
grpc/shared_conn.go
Outdated
|
||
ret.peerConn.OnTrack(func(trackRemote *webrtc.TrackRemote, rtpReceiver *webrtc.RTPReceiver) { | ||
sid := trackRemote.StreamID() | ||
if sid == "rtsp-1" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets sync in person about this
grpc/shared_conn.go
Outdated
|
||
ret.peerConn.OnTrack(func(trackRemote *webrtc.TrackRemote, rtpReceiver *webrtc.RTPReceiver) { | ||
sid := trackRemote.StreamID() | ||
if sid == "rtsp-1" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
robot/client/client.go
Outdated
@@ -268,6 +275,7 @@ func New(ctx context.Context, address string, clientLogger logging.ZapCompatible | |||
sessionsDisabled: rOpts.disableSessions, | |||
heartbeatCtx: heartbeatCtx, | |||
heartbeatCtxCancel: heartbeatCtxCancel, | |||
isModuleConnection: rOpts.modName != "", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see where isModuleConnection
is used. Do we intend to use this in an upcoming PR? If so, how?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching that. That was a leftover from hacking that I decided not to use, but missed in the cleanup.
// | ||
// Modules talking back to the viam-server for a camera stream should use the "short | ||
// name"/`SDPTrackName` (i.e: `foo`). | ||
if sc, ok := c.conn.(*grpc.SharedConn); ok && sc.IsConnectedToModule() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic change for knowing when to use a full resource name
} | ||
|
||
// IsConnectedToModule returns whether this shared conn is being used to communicate with a module. | ||
func (sc *SharedConn) IsConnectedToModule() bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created two methods for this because I didn't think it was obvious this was indeed binary? And I like to read these descriptions in the affirmative tense
No description provided.